package com.ruibang.glass.produce.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruibang.glass.common.constants.RedisKey;
import com.ruibang.glass.common.utils.DateUtils;
import com.ruibang.glass.produce.constant.Constants;
import com.ruibang.glass.produce.domain.req.FlowInfo;
import com.ruibang.glass.produce.domain.req.FlowRateTrendReq;
import com.ruibang.glass.produce.domain.req.ThicknessTrendReq;
import com.ruibang.glass.produce.domain.req.TrafficTrendReq;
import com.ruibang.glass.produce.domain.resp.*;
import com.ruibang.glass.produce.entity.ThicknessTrendRule;
import com.ruibang.glass.produce.mapper.HotRealTimeMapper;
import com.ruibang.glass.produce.service.HotRealTimeService;
import com.ruibang.glass.produce.service.ThicknessTrendRuleService;
import com.ruibang.glass.produce.util.DataUtil;
import com.ruibang.glass.produce.util.ExcelStyleUtils;
import com.teaming.cloud.framework2.autoconfigure.redis.RedisSingleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author: songJinKang
 * @CreateTime: 2023-11-23  15:56
 * @Description: TODO
 * @Version: 1.0
 */
@Slf4j
@Service
public class HotRealTimeServiceImpl extends ServiceImpl<HotRealTimeMapper, Object> implements HotRealTimeService {

    @Autowired
    private ThicknessTrendRuleService thicknessTrendRuleService;

    @Autowired
    private RedisSingleService redisService;


    @Override
    public Page<ThicknessTrendBase> thicknessTrend(ThicknessTrendReq thicknessTrendReq) {
        if (thicknessTrendReq.getStartTime() != null && thicknessTrendReq.getEndTime() != null) {
            thicknessTrendReq.setEndTimeTs(thicknessTrendReq.getEndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli());
            thicknessTrendReq.setStartTimeTs(thicknessTrendReq.getStartTime().toInstant(ZoneOffset.of("+8")).toEpochMilli());
        } else {
            LocalDateTime now = LocalDateTime.now();
            long end = now.toInstant(ZoneOffset.of("+8")).toEpochMilli();
            long start = now.minusDays(1).toInstant(ZoneOffset.of("+8")).toEpochMilli();
            thicknessTrendReq.setEndTimeTs(end);
            thicknessTrendReq.setStartTimeTs(start);
        }

        IPage<Map<String, String>> page = baseMapper.thicknessTrend(new Page<>(thicknessTrendReq.getPageNo(), thicknessTrendReq.getPageSize()), thicknessTrendReq);

        //获取规则
        ThicknessTrendRule thicknessTrendRule = null;
        if (StringUtils.isNotBlank(thicknessTrendReq.getRuleId())) {
            thicknessTrendRule = thicknessTrendRuleService.getById(thicknessTrendReq.getRuleId());
        }

        if (page != null && CollectionUtils.isNotEmpty(page.getRecords())) {
            List<ThicknessTrendBase> thicknessTrendBases = new ArrayList<>();
            for (Map<String, String> resultMap : page.getRecords()) {
                ThicknessTrendBase thicknessTrendBase = new ThicknessTrendBase();

                //获取230测点
                List<Double> values = new ArrayList<>();
                for (int i = 1; i < 231; i++) {
                    String measurePoint = String.format(Constants.MEASURE_PINT_KEY, i);
                    String value = resultMap.get(measurePoint);
                    if (value.length() > 10) {
                        values.add(Double.valueOf(String.format("%.3f", Double.parseDouble(value))));
                    } else {
                        values.add(Double.valueOf(value));
                    }
                }

                //玻璃id
                String hotId = resultMap.get("_id");
                thicknessTrendBase.setGlassId(hotId);


                //计算平均、最大、最小、极值
                double avg = values.stream().mapToDouble(Double::valueOf).average().getAsDouble();
                double max = values.stream().filter(e -> e != 0).mapToDouble(Double::valueOf).max().getAsDouble();
                double min = values.stream().filter(e -> e != 0).mapToDouble(Double::valueOf).min().getAsDouble();
                thicknessTrendBase.setAvg(avg);
                thicknessTrendBase.setMax(max);
                thicknessTrendBase.setMin(min);
                double peak = Double.parseDouble(String.format("%.3f", max - min));
                thicknessTrendBase.setPeak(peak);

                //判断是否合格
                if (thicknessTrendRule != null) {
                    String status = qualifiedOrNot(thicknessTrendRule, thicknessTrendBase.getAvg(), thicknessTrendBase.getMax(), thicknessTrendBase.getMin(), thicknessTrendBase.getPeak());
                    thicknessTrendBase.setDetermine(status);
                }

                //测点
                thicknessTrendBase.setValues(values);

                //获取横切时间
                Object timeObj = redisService.hget(RedisKey.HOT_ID_MAPPING_STATION_START_TIME_KEY, hotId);
                if (timeObj != null && StringUtils.isNotBlank(timeObj.toString())) {
                    thicknessTrendBase.setStationStartTime(DateUtils.stringToLocalDateTime(timeObj.toString(), com.ruibang.glass.common.constants.Constants.DATE_TIME_FORMATTER_STR));
                }

                thicknessTrendBases.add(thicknessTrendBase);
            }

            //排序
            thicknessTrendBases = thicknessTrendBases.stream().sorted(Comparator.comparing(ThicknessTrendBase::getStationStartTime, Comparator.nullsLast(Comparator.reverseOrder()))).collect(Collectors.toList());

            //分页处理
            Page<ThicknessTrendBase> pageData = new Page<>();
            pageData.setRecords(thicknessTrendBases);
            pageData.setTotal(page.getTotal());
            pageData.setSize(page.getSize());
            pageData.setCurrent(page.getCurrent());
            pageData.setPages(page.getPages());
            return pageData;
        }
        return new Page<>();
    }


    /**
     * @Description: 效验是否合格
     * @version v1.0
     * @author songJinKang
     * @date 2024-02-05 19:30
     */
    private String qualifiedOrNot(ThicknessTrendRule thicknessTrendRule, double avg, double max, double min, double peak) {
        switch (thicknessTrendRule.getPeakLogicalSymbol()) {
            case ">": {
                if (peak > thicknessTrendRule.getPeak()) {
                    if (ruleScopeJudgment(thicknessTrendRule, avg, max, min)) {
                        return Constants.ONE_STR;
                    }
                }
                break;
            }
            case "<": {
                if (peak < thicknessTrendRule.getPeak()) {
                    if (ruleScopeJudgment(thicknessTrendRule, avg, max, min)) {
                        return Constants.ONE_STR;
                    }
                }
                break;
            }
            case "≥": {
                if (peak >= thicknessTrendRule.getPeak()) {
                    if (ruleScopeJudgment(thicknessTrendRule, avg, max, min)) {
                        return Constants.ONE_STR;
                    }
                }
                break;
            }
            case "≤": {
                if (peak <= thicknessTrendRule.getPeak()) {
                    if (ruleScopeJudgment(thicknessTrendRule, avg, max, min)) {
                        return Constants.ONE_STR;
                    }
                }
                break;
            }
            default:
                return Constants.ZERO_STR;
        }
        return Constants.ZERO_STR;
    }

    private boolean ruleScopeJudgment(ThicknessTrendRule thicknessTrendRule, double avg, double max, double min) {
        if ((avg >= (double) thicknessTrendRule.getMinAvg() / 1000 && avg <= (double) thicknessTrendRule.getMaxAvg() / 1000) &&
                (max >= (double) thicknessTrendRule.getMaxDown() / 1000 && max <= (double) thicknessTrendRule.getMaxUp() / 1000) &&
                (min >= (double) thicknessTrendRule.getMinDown() / 1000 && min <= (double) thicknessTrendRule.getMinUp() / 1000)
        ) {
            return true;
        }
        return false;
    }

    @Override
    public FlowRateTrendBase flowRateTrend(FlowRateTrendReq flowRateTrendReq) {
        //默认查询一天
        long start;
        long end;
        if (flowRateTrendReq.getStartTime() == null || flowRateTrendReq.getEndTime() == null) {
            LocalDateTime now = LocalDateTime.now();
            end = now.toInstant(ZoneOffset.of("+8")).toEpochMilli();
            start = now.minusDays(1).toInstant(ZoneOffset.of("+8")).toEpochMilli();
        } else {
            end = flowRateTrendReq.getEndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
            start = flowRateTrendReq.getStartTime().minusDays(1).toInstant(ZoneOffset.of("+8")).toEpochMilli();
        }
        //获取流速数据
        FlowRateTrendBase flowRateTrendBase = new FlowRateTrendBase();
        List<FlowRateTrendData> flowRateTrendData = baseMapper.flowRateTrend(String.valueOf(start), String.valueOf(end));

        if (CollectionUtils.isNotEmpty(flowRateTrendData)) {
            flowRateTrendBase.setFlowRateTrendData(flowRateTrendData);
            List<Double> values = flowRateTrendData.stream().map(FlowRateTrendData::getValue).collect(Collectors.toList());
            //计算平均、最大、最小值
            double avg = values.stream().mapToDouble(Double::valueOf).average().getAsDouble();
            double max = values.stream().filter(e -> e != 0).mapToDouble(Double::valueOf).max().getAsDouble();
            double min = values.stream().filter(e -> e != 0).mapToDouble(Double::valueOf).min().getAsDouble();
            flowRateTrendBase.setAvg(avg);
            flowRateTrendBase.setMax(max);
            flowRateTrendBase.setMin(min);
        }

        //刀头压力、切割长度
        CutterHeadSlicingData cutterHeadSlicingData = baseMapper.getDcData();
        flowRateTrendBase.setCutterHeadSlicingData(cutterHeadSlicingData);
        return flowRateTrendBase;
    }

    @Override
    public List<WeighingTrendBase> weighingTrend(FlowRateTrendReq flowRateTrendReq) {
        if (flowRateTrendReq.getStartTime() == null || flowRateTrendReq.getEndTime() == null) {
            LocalDateTime now = LocalDateTime.now();
            flowRateTrendReq.setEndTime(now);
            flowRateTrendReq.setStartTime(now.minusDays(1));
        }
        return baseMapper.weighingTrend(flowRateTrendReq);
    }


    @Override
    public TrafficTrendBase trafficTrend(TrafficTrendReq trafficTrendReq) {
        if (trafficTrendReq.getStartTime() == null || trafficTrendReq.getEndTime() == null) {
            LocalDateTime now = LocalDateTime.now();
            trafficTrendReq.setEndTime(now);
            trafficTrendReq.setStartTime(now.minusDays(1));
        }

        TrafficTrendBase trafficTrendBase = new TrafficTrendBase();

        //获取 板重、节拍
        List<Flows> flows = baseMapper.queryTrafficTrend(trafficTrendReq);

        List<String> collectTimeList = new ArrayList<>();

        if (CollectionUtils.isNotEmpty(flows)) {
            FlowInfo flowInfo = new FlowInfo();

            //处理数据
            flows = flows.stream().filter(DataUtil.distinctByKey(Flows::getCollectTime)).collect(Collectors.toList());

            //采集时间
            List<String> collectTime = flows.stream().map(Flows::getCollectTime).collect(Collectors.toList());
            collectTimeList.addAll(collectTime);
            flowInfo.setCollectTime(collectTime);

            //计算流量 3600/节拍*板重
            List<Double> flowsValue = new ArrayList<>();
            for (Flows flow : flows) {
                if (flow.getPlateWeight() != null && flow.getBeat() != null) {
                    double avg = 3600 / flow.getPlateWeight() * flow.getBeat();
                    flowsValue.add(Double.valueOf(String.format("%.3f", avg)));
                }
            }
            flowInfo.setFlow(flowsValue);

            //计算平均值
            List<Double> avgValue = new ArrayList<>();
            for (int i = 0; i < flowsValue.size(); i++) {
                double sum = 0;
                int count = 0;
                // 计算从当前元素开始，向前最多6个元素的总和
                for (int j = i; j >= 0 && j > i - 7; j--) {
                    sum += flowsValue.get(j);
                    count++;
                }
                if (count > 0) {
                    double avg = sum / count;
                    // 计算平均值
                    avgValue.add(Double.valueOf(String.format("%.3f", avg)));
                }
            }
            flowInfo.setAvg(avgValue);
            trafficTrendBase.setFlowInfo(flowInfo);
        }

        //液位
        List<HotRealTimeLiquidLevel> liquidLevel = baseMapper.queryLiquidLevel(trafficTrendReq);
        if (CollectionUtils.isNotEmpty(liquidLevel)) {
            trafficTrendBase.setLiquidLevel(liquidLevel.stream().filter(DataUtil.distinctByKey(HotRealTimeLiquidLevel::getCollectTime)).collect(Collectors.toList()));
            List<String> collectTime = liquidLevel.stream().map(HotRealTimeLiquidLevel::getCollectTime).collect(Collectors.toList());
            collectTimeList.addAll(collectTime);
        }

        //投料频率
        List<HotRealTimeFeedingFrequency> feedingFrequency = baseMapper.queryFeedingFrequency(trafficTrendReq);
        if (CollectionUtils.isNotEmpty(feedingFrequency)) {
            trafficTrendBase.setFeedingFrequency(feedingFrequency.stream().filter(DataUtil.distinctByKey(HotRealTimeFeedingFrequency::getCollectTime)).collect(Collectors.toList()));
            List<String> collectTime = feedingFrequency.stream().map(HotRealTimeFeedingFrequency::getCollectTime).collect(Collectors.toList());
            collectTimeList.addAll(collectTime);
        }

        //处理时间列表
        if (CollectionUtils.isNotEmpty(collectTimeList)) {
            collectTimeList = collectTimeList.stream().filter(DataUtil.distinctByKey(e -> e)).sorted().collect(Collectors.toList());
            trafficTrendBase.setCollectTimeList(collectTimeList);
        }

        return trafficTrendBase;
    }

    @Override
    public void exportForceCutLength(FlowRateTrendReq flowRateTrendReq, HttpServletResponse response) {
        long start;
        long end;
        if (flowRateTrendReq.getStartTime() == null || flowRateTrendReq.getEndTime() == null) {
            LocalDateTime now = LocalDateTime.now();
            end = now.toInstant(ZoneOffset.of("+8")).toEpochMilli();
            start = now.minusDays(1).toInstant(ZoneOffset.of("+8")).toEpochMilli();
        } else {
            end = flowRateTrendReq.getEndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
            start = flowRateTrendReq.getStartTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        }
        List<CutterHeadSlicingData> cutterHeadSlicingDataList = baseMapper.exportForceCutLength(start, end);

        if (CollectionUtils.isNotEmpty(cutterHeadSlicingDataList)) {
            try {
                EasyExcel.write(response.getOutputStream(), CutterHeadSlicingData.class)
                        .registerWriteHandler(ExcelStyleUtils.createTableStyle())
                        .sheet("刀压切割长度数据").doWrite(cutterHeadSlicingDataList);
            } catch (IOException ex) {
                log.error("数据导出失败：{}", ex.getMessage());
            }
        }
    }

    @Override
    public IPage<CutterHeadSlicingData> queryForceCutLengthData(FlowRateTrendReq flowRateTrendReq) {
        long start;
        long end;
        if (flowRateTrendReq.getStartTime() == null || flowRateTrendReq.getEndTime() == null) {
            LocalDateTime now = LocalDateTime.now();
            end = now.toInstant(ZoneOffset.of("+8")).toEpochMilli();
            start = now.minusDays(1).toInstant(ZoneOffset.of("+8")).toEpochMilli();
        } else {
            end = flowRateTrendReq.getEndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
            start = flowRateTrendReq.getStartTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        }
        return baseMapper.queryForceCutLengthData(new Page<>(flowRateTrendReq.getPageNo(), flowRateTrendReq.getPageSize()), start, end);
    }
}
